package com.open.harmony.common.image;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.open.harmony.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Configuration
//@ConfigurationProperties(prefix = "zimg")
public class ImageConfig {
    @Value("${zimg.server}")
    private String server;
    @Value("${zimg.upload-path}")
    private String uploadPath;
    @Value("${zimg.delete-path}")
    private String deletePath;
    @Value("${zimg.max-size}")
    private Integer maxSize;
    @Value("${zimg.max-size-per-img}")
    private Integer maxSizePerImage;
    @Value("${zimg.allow-format}")
    private String allowFormats;

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public ImageDao imageDao(){
        return new ImageDao() {
            List<String> formats;

            @Override
            public void init() throws Exception{
                // spring容器启动时调用一次
                if(null==server){
                    log.error("zimg配置缺少服务器地址(server)异常");
                    throw new Exception("zimg配置缺少服务器地址(server)异常");
                }
                if(null==uploadPath){
                    log.error("zimg配置缺少上传api路径(upload-path)异常");
                    throw new Exception("zimg配置缺少上传api路径(upload-path)异常");
                }
                if(null==deletePath){
                    log.error("zimg配置缺少删除api路径(delete-path)异常");
                    throw new Exception("zimg配置缺少删除api路径(delete-path)异常");
                }
                if(null==maxSize){
                    log.error("zimg配置缺少单次上传允许总容量(max-size)异常");
                    throw new Exception("zimg配置缺少单次上传允许总容量(max-size)异常");
                }
                if(null==maxSizePerImage){
                    log.error("zimg配置缺少单个文件允许上传容量(max-size-per-formats)异常");
                    throw new Exception("zimg配置缺少单个文件允许上传容量(max-size-per-formats)异常");
                }
                if(maxSize<maxSizePerImage){
                    log.error("zimg配置总容量(max-size)小于单个文件容量(max-size-per-image)异常");
                    throw new Exception("zimg配置总容量(max-size)小于单个文件容量(max-size-per-image)异常");
                }
                if(null==allowFormats || !allowFormats.matches("^[a-z]{3,4}(,[a-z]{3,4})*$")){
                    log.error("zimg配置缺少允许图像格式(allow-formats)或内容格式异常");
                    throw new Exception("zimg配置缺少允许图像格式(allow-formats)或内容格式异常");
                }

                formats = new ArrayList(Arrays.asList(allowFormats.split(",")));
            }

            @Override
            public void destroy() {
                // spring容器销毁时调用一次
                if(null != formats && formats.isEmpty()){
                    formats.clear();
                    formats = null;
                }
            }

            private void close(AutoCloseable...acs){
                for (AutoCloseable ac : acs) {
                    if(null != ac){
                        try {
                            ac.close();
                        } catch (Exception e) {
                            log.error("释放资源异常",e);
                        }
                    }
                }
            }

            @Override
            public Result upload(MultipartFile file) {
                Result msg = Result.error("图片上传失败");
                // image/png
                String contentType = file.getContentType().toLowerCase();
                contentType = contentType.substring(contentType.indexOf("/")+1);
                if(formats.contains(contentType)){
                    if(file.getSize()<maxSizePerImage){
                        HttpPost post = new HttpPost(URI.create(String.format("%s%s",server,uploadPath)));
                        post.setHeader("Content-Type",contentType);
                        CloseableHttpClient http = HttpClients.createDefault();
                        CloseableHttpResponse response = null;
                        try {
                            post.setEntity(new ByteArrayEntity(file.getBytes()));
                            response = http.execute(post);
                            HttpEntity entity = response.getEntity();
                            String json = EntityUtils.toString(entity);
                            JSONObject jsonObj = JSON.parseObject(json);
                            Boolean ret = jsonObj.getBoolean("ret");
                            if(ret){
                                String md5 = jsonObj.getJSONObject("info").getString("md5");
                                msg = Result.success(md5);
                            }
                        } catch (IOException e) {
                            log.error("zimg单个文件上传异常",e);
                            return Result.error(e.toString());
                        }finally {
                            close(response, http);
                        }
                    }
                    else{
                        msg = Result.error(String.valueOf(new RuntimeException("单个上传文件必须小于等于 "+maxSizePerImage+" 字节")));
                    }
                }else{
                    msg = Result.error(String.valueOf(new RuntimeException("仅支持[ "+allowFormats+" ]格式图片上传")));
                }
                return msg;
            }

            @Override
            public Result upload(MultipartFile[] files) {
                long totalSize = 0;
                for (MultipartFile file : files) {
                    if(null == file || file.getSize()==0){
                        return Result.error(String.valueOf(new RuntimeException("上传图片内容为空")));
                    }
                    if(!formats.contains(file.getContentType().toLowerCase())){
                        return Result.error(String.valueOf(new RuntimeException("仅支持[ "+allowFormats+" ]格式图片上传")));
                    }
                    if(file.getSize()>maxSizePerImage){
                        return Result.error(String.valueOf(new RuntimeException("单个上传文件必须小于等于 "+maxSizePerImage+" 字节")));
                    }
                    if((totalSize+=file.getSize())>maxSize){
                        return Result.error(String.valueOf(new RuntimeException("总容量必须小于 "+maxSize+" 字节")));
                    }
                }
                Result msg = Result.error("图片上传失败");
                CloseableHttpClient http = HttpClients.createDefault();
                URI uri = URI.create(String.format("%s%s",server,uploadPath));
                List<String> successMd5s = new ArrayList<>(files.length);
                try{
                    for (MultipartFile file : files) {
                        HttpPost post = new HttpPost(uri);
                        post.setHeader("Content-Type",file.getContentType());
                        post.setEntity(new ByteArrayEntity(file.getBytes()));
                        CloseableHttpResponse response = http.execute(post);
                        HttpEntity entity = response.getEntity();
                        String json = EntityUtils.toString(entity);
                        close(response);
                        JSONObject jsonObj = JSON.parseObject(json);
                        Boolean ret = jsonObj.getBoolean("ret");
                        if(ret){
                            String md5 = jsonObj.getJSONObject("info").getString("md5");
                            successMd5s.add(md5);
                            continue;
                        }
                        throw new RuntimeException("文件"+file.getOriginalFilename()+"上传失败");
                    }
                    msg = Result.success(successMd5s);
                }catch(Exception e){
                    log.error("多个文件上传异常",e);
                    if(!successMd5s.isEmpty()){
                        successMd5s.forEach(md5 -> delete(md5));
                    }
                    msg = Result.error(String.valueOf(e));
                } finally {
                    close(http);
                }

                return msg;
            }

            @Override
            public Result delete(String md5) {
                if(null == md5 || md5.length() != 32){
                    return Result.error("md5长度必须为32位");
                }
                Result msg = Result.error("删除图片失败");
                URIBuilder builder = new URIBuilder(URI.create(String.format("%s%s",server,deletePath)));
                builder.addParameter("md5",md5);
                builder.addParameter("t","1");
                CloseableHttpClient http = HttpClients.createDefault();
                CloseableHttpResponse response = null;
                try {
                    HttpGet get = new HttpGet(builder.build());
                    response = http.execute(get);
                    HttpEntity entity = response.getEntity();
                    String result = EntityUtils.toString(entity);
                    if(result.contains("Successful")){
                        msg = Result.success("删除图片成功");
                    }
                } catch (Exception e) {
                    log.error("zimg删除图片异常:"+md5, e);
                }finally {
                    close(http,response);
                }
                return msg;
            }
        };
    }
}
